﻿using System;
using System.Reflection;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace FsAddInManager
{
    public sealed class AIM
    {
        public Result ExecuteCommand(ExternalCommandData data, ref string message, ElementSet elements, bool faceless)
        {
            if (this.m_activeCmd != null && faceless)
            {
                return this.RunActiveCommand(data, ref message, elements);
            }

            using (MainForm mainForm = new MainForm(this))
            {
                if (DialogResult.OK != mainForm.ShowDialog())
                {
                    return Autodesk.Revit.UI.Result.Cancelled;
                }
            }

            if (this.m_activeCmd != null)
            {
                return this.RunActiveCommand(data, ref message, elements);
            }

            return Autodesk.Revit.UI.Result.Failed;
        }

        public string ActiveTempFolder
        {
            get { return this.m_activeTempFolder; }
            set { this.m_activeTempFolder = value; }
        }

        private Result RunActiveCommand(ExternalCommandData data, ref string message, ElementSet elements)
        {
            string filePath = this.m_activeCmd.FilePath;
            AssemLoader assemLoader = new AssemLoader();
            Result result;
            try
            {
                assemLoader.HookAssemblyResolve();
                Assembly assembly = assemLoader.LoadAddinsToTempFolder(filePath, false);
                if (null == assembly)
                {
                    result = Autodesk.Revit.UI.Result.Failed;
                }
                else
                {
                    this.m_activeTempFolder = assemLoader.TempFolder;
                    IExternalCommand externalCommand = assembly.CreateInstance(this.m_activeCmdItem.FullClassName) as IExternalCommand;
                    if (externalCommand == null)
                    {
                        result = Autodesk.Revit.UI.Result.Failed;
                    }
                    else
                    {
                        this.m_activeEC = externalCommand;
                        result = this.m_activeEC.Execute(data, ref message, elements);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                result = Autodesk.Revit.UI.Result.Failed;
            }
            finally
            {
                assemLoader.UnhookAssemblyResolve();
                assemLoader.CopyGeneratedFilesBack();
            }

            return result;
        }

        public static AIM Instance
        {
            get
            {
                if (AIM.m_inst == null)
                {
                    lock (typeof(AIM))
                    {
                        if (AIM.m_inst == null)
                        {
                            AIM.m_inst = new AIM();
                        }
                    }
                }

                return AIM.m_inst;
            }
        }

        private AIM()
        {
            this.m_addinManager = new AddinManager();
            this.m_activeCmd = null;
            this.m_activeCmdItem = null;
            this.m_activeApp = null;
            this.m_activeAppItem = null;
        }

        public IExternalCommand ActiveEC
        {
            get { return this.m_activeEC; }
            set { this.m_activeEC = value; }
        }

        public Addin ActiveCmd
        {
            get { return this.m_activeCmd; }
            set { this.m_activeCmd = value; }
        }

        public AddinItem ActiveCmdItem
        {
            get { return this.m_activeCmdItem; }
            set { this.m_activeCmdItem = value; }
        }

        public Addin ActiveApp
        {
            get { return this.m_activeApp; }
            set { this.m_activeApp = value; }
        }

        public AddinItem ActiveAppItem
        {
            get { return this.m_activeAppItem; }
            set { this.m_activeAppItem = value; }
        }

        public AddinManager AddinManager
        {
            get { return this.m_addinManager; }
            set { this.m_addinManager = value; }
        }

        private string m_activeTempFolder = string.Empty;

        private static volatile AIM m_inst;

        private IExternalCommand m_activeEC;

        private Addin m_activeCmd;

        private AddinItem m_activeCmdItem;

        private Addin m_activeApp;

        private AddinItem m_activeAppItem;

        private AddinManager m_addinManager;
    }
}